/*
    QArv, a Qt interface to aravis.
    Copyright (C) 2012, 2013 Jure Varlec <jure.varlec@ad-vega.si>
                             Andrej Lajovic <andrej.lajovic@ad-vega.si>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef QARVDECODER_H
#define QARVDECODER_H

#include <gio/gio.h>  // Workaround for gdbusintrospection's use of "signal".
#include <QByteArray>
#include <QString>
#include <QSize>
#include <QImage>
#include <QtPlugin>
#include <opencv2/core/core.hpp>
extern "C" {
#include <libavutil/pixfmt.h>
}

#pragma GCC visibility push(default)

#ifndef ARV_PIXEL_FORMAT_MONO_8
typedef quint32 ArvPixelFormat;
#endif

//! An abstract interface of a decoder for a particular frame format and size.
/*!
 * Decoder instances are generated by plugins implementing the QArvPixelFormat
 * interface.
 */
class QArvDecoder {
public:
    virtual ~QArvDecoder() {};

    //! Decodes the given frame.
    virtual void decode(QByteArray frame) = 0;

    /*!
     * Returns the decoded frame as an OpenCv matrix. See cvType() for possible
     * types. The matrix is constant to avoid copying. It references data
     * internal to the decoder which is overwritten when decode() is called,
     * so make sure you copy the matrix or otherwise finish using it before
     * decoding another frame.
     */
    virtual const cv::Mat getCvImage() = 0;

    /*!
     * Returns the type of cv::Mat returned by getCvImage(). The decoder chooses
     * the most sensible type given the number of significant bits in input data.
     * Possible types are either CV_8U or CV_16U, with 1 or 3 channels.
     */
    virtual int cvType() = 0;

    //! Returns the pixel format supported by this decoder.
    virtual ArvPixelFormat pixelFormat() = 0;

    //! Returns an opaque token that can be used to create another instance of this decoder.
    virtual QByteArray decoderSpecification() = 0;

    /*!
     * Convenience function to convert an OpenCV image to QImage. Limited to
     * formats used by QArv (see cvType()). Returns Format_ARGB32_Premultiplied,
     * which is fast to render.
     */
    static void CV2QImage(const cv::Mat& image, QImage& out);
    static QImage CV2QImage(const cv::Mat& image);

    /*!
     * Alternative version of CV2QImage() which returns either Format_RGB888
     * or Format_Indexed8, which may be easier to use for direct pixel
     * manipulation, but are slow to render. Not recommended, for manipulation
     * cv::Mat should be used instead.
     */
    static void CV2QImage_RGB24(const cv::Mat& image, QImage& out);
    static QImage CV2QImage_RGB24(const cv::Mat& image);

    //! Uses the token returned by Decoder::decoderSpecification() to create another instance.
    static QArvDecoder* makeDecoder(QByteArray specification);

    /*!
     * Creates a decoder for the requested format and frame size.
     * Some decoders allow using a faster algorithm for decoding colors,
     * which can be (but is not neccessarily) less precise.
     */
    static QArvDecoder* makeDecoder(ArvPixelFormat, QSize size,
                                    bool fast = true);

    //! Convenience function to create a libswscale decoder, not limited to Aravis pixel formats.
    static QArvDecoder* makeSwScaleDecoder(enum AVPixelFormat fmt,
                                           QSize size,
                                           int swsFlags = 0);
};

//! Interface for the plugin to generate a decoder for a particular format.
class QArvPixelFormat {
public:
    virtual ~QArvPixelFormat() {};

    //! Returns the Aravis' name for the pixel format supported by this plugin.
    virtual ArvPixelFormat pixelFormat() = 0;

    //! Instantiates a decoder using this plugin.
    virtual QArvDecoder* makeDecoder(QSize size) = 0;

    //! Returns the list of supported pixel formats.
    static QList<ArvPixelFormat> supportedFormats();
};

Q_DECLARE_INTERFACE(QArvPixelFormat,
                    "si.ad-vega.qarv.QArvPixelFormat/0.1")

#pragma GCC visibility pop

#endif
